package com.mall.common.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;

/**
 * 二维码生成工具类
 * @author zengjintao
 * @version 1.0
 * @create 2018-08-08 19:34
 **/
public class QrCodeGenerate {

    private static final String CHARSET = "utf-8";
    // 二维码尺寸
    private static final int QRCODE_SIZE = 600;
    // LOGO宽度
    private static final int WIDTH = 160; //宽度固定
    // LOGO高度
    @SuppressWarnings({ "unused"})
	private static final int HEIGHT = 60;

    @SuppressWarnings("unused")
	private String content; //二维码内容

    @SuppressWarnings("unused")
	private String logoPath; //logo路径

    private BufferedImage bufferedImage;

    public QrCodeGenerate(String content, String logoPath) {
       this(content,logoPath,true);
    }

    public QrCodeGenerate(String content, String logoPath, boolean needCompress) {
        this.content = content;
        this.logoPath = logoPath;
        this.bufferedImage = createImage(content, logoPath, needCompress);
    }

    public static void createQrCode(String content,String filePath) throws WriterException {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = null;
        BufferedImage image = null;
        try {
            bitMatrix = new MultiFormatWriter().encode(content,
                    BarcodeFormat.QR_CODE, 320, 320, hints);
            int width = bitMatrix.getWidth();
            int height = bitMatrix.getHeight();
            image = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000
                            : 0xFFFFFFFF);
                }
            }
            ImageIO.write(image, "jpeg", new File(filePath));
        }catch (Exception e){
           e.printStackTrace();
        }
    }

    private BufferedImage createImage(String content, String logoPath,
                                      boolean needCompress){
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = null;
        BufferedImage image = null;
        try {
            bitMatrix = new MultiFormatWriter().encode(content,
                    BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
            int width = bitMatrix.getWidth();
            int height = bitMatrix.getHeight();
            image = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000
                            : 0xFFFFFFFF);
                }
            }
            if (logoPath == null || "".equals(logoPath)) {
                return image;
            }
            // 插入图片
            insertImage(image, logoPath, needCompress);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return image;
    }

    /**
     * 插入LOGO
     *
     * @param source
     *            二维码图片
     * @param logoPath
     *            LOGO图片地址
     * @param needCompress
     *            是否压缩
     * @throws Exception
     */
    private void insertImage(BufferedImage source, String logoPath,
                                    boolean needCompress) throws Exception {
        File file = new File(logoPath);
        if (!file.exists()) {
            System.err.println("" + logoPath +"该文件不存在！");
            return;
        }
        Image src = ImageIO.read(file);
        int width = src.getWidth(null);
        int height = src.getHeight(null);

        if (needCompress) { // 压缩LOGO
            height = WIDTH * height / width;
            width = WIDTH;
            Image image = src.getScaledInstance(width, height,
                    Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);

            Graphics2D g2d = tag.createGraphics();
            g2d.setBackground(Color.green);
            g2d.setPaint(Color.BLACK);

            Shape shape = new RoundRectangle2D.Float(0, 0, width / 2, height, 20, 20);

            g2d.fill(shape);
            g2d.dispose();
            src = image;
        }
        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;

        graph.setPaint(Color.white);

        Shape iconBackgroundShape = new RoundRectangle2D.Float(x, y, width, height, 30, 30);
        graph.fill(iconBackgroundShape);
        graph.drawImage(src, x + 10, y + 10, width - 20, height - 20, null);
        // 画边框
        Shape borderShape = new RoundRectangle2D.Float(x + 9, y + 9, width - 18, height - 18, 30, 30);
        graph.setStroke(new BasicStroke(1f));
        graph.setColor(Color.gray);
        graph.setBackground(Color.white);
        graph.draw(borderShape);
        graph.dispose();
    }

    /**
     * 生成带logo的二维码
     * @param qrCodePath   logo二维码路径
     */
    public void generateQrCode(String qrCodePath){
        try {
            ImageIO.write(this.bufferedImage, "jpeg", new File(qrCodePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
